package com.buaa.schedule;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.buaa.entity.Address;
import com.buaa.entity.TrafficCaseInfo;
import com.buaa.mapper.AddressMapper;
import com.buaa.mapper.TrafficCaseInfoMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Component
@RequiredArgsConstructor
public class HandleCaseInfoAddress {

    private final TrafficCaseInfoMapper trafficCaseInfoMapper;

    private final AddressMapper addressMapper;

    @Scheduled(cron = "0 */1 * * * *")
    public void handleProvince() {
        handle("province");
    }

    @Scheduled(cron = "1 */1 * * * *")
    public void handleCity() {
        handle("city");
    }

    @Scheduled(cron = "2 */1 * * * *")
    public void handleDistrict() {
        handle("district");
    }

    @Scheduled(cron = "30 */1 * * * *")
    public void handleEmptyCity() {
        Page<TrafficCaseInfo> page = new Page<>(0, 500);
        QueryWrapper<TrafficCaseInfo> queryWrapper = new QueryWrapper<>();
        page.setRecords(trafficCaseInfoMapper.selectList(queryWrapper.isNull("city_id").isNotNull("district_id")));
        List<TrafficCaseInfo> records = page.getRecords();

        QueryWrapper<Address> addressQueryWrapper = new QueryWrapper<>();
        Set<Integer> addressIds = records.stream().map(TrafficCaseInfo::getDistrictId).collect(Collectors.toSet());
        List<Address> address = addressMapper.selectList(addressQueryWrapper.in("id", addressIds));

        Map<Integer, Address> addressMap = address.stream().collect(Collectors.toMap(Address::getId, Function.identity()));

        // 更新数据
        for (TrafficCaseInfo trafficCaseInfo : records) {
            TrafficCaseInfo updateCaseInfo = new TrafficCaseInfo();
            Address districtAddress = addressMap.get(trafficCaseInfo.getDistrictId());
            updateCaseInfo.setCityId(districtAddress.getPid());
            UpdateWrapper<TrafficCaseInfo> updateWrapper = new UpdateWrapper<>();
            updateWrapper.eq("id",trafficCaseInfo.getId());
            trafficCaseInfoMapper.update(updateCaseInfo,updateWrapper);
        }
    }

    private void handle(String type) {
        QueryWrapper<TrafficCaseInfo> queryWrapper = new QueryWrapper<>();

        String field;
        switch (type) {
            default:
            case "province":
                field = "province_id";
                break;
            case "city":
                field = "city_id";
                break;
            case "district":
                field = "district_id";
                break;
        }

        while (true) {
            Page<TrafficCaseInfo> page = new Page<>(0, 500);

            page.setRecords(trafficCaseInfoMapper.selectList(queryWrapper.isNull(field)));

            List<TrafficCaseInfo> records = page.getRecords();

            if (records.isEmpty()) {
                break;
            }

            Set<String> addresses;
            QueryWrapper<Address> addressQueryWrapper = new QueryWrapper<>();
            List<Address> address;
            switch (type) {
                default:
                case "province":
                    addresses = records.stream().map(TrafficCaseInfo::getCaseProvince).collect(Collectors.toSet());
                    address = addressMapper.selectList(addressQueryWrapper.in("name", addresses).eq("level", "province"));
                    break;
                case "city":
                    addresses = records.stream().map(TrafficCaseInfo::getCaseCity).collect(Collectors.toSet());
                    address = addressMapper.selectList(addressQueryWrapper.in("name", addresses).eq("level", "city"));
                    break;
                case "district":
                    addresses = records.stream().map(TrafficCaseInfo::getCaseArea).collect(Collectors.toSet());
                    address = addressMapper.selectList(addressQueryWrapper.in("name", addresses).eq("level", "district"));
                    break;
            }

            Map<String, Address> addressMap = address.stream().collect(Collectors.toMap(Address::getName, Function.identity()));

            Map<Integer, List<Integer>> updateData = generateUpdateData(records,addressMap,type);

            if (updateData.isEmpty()) {
                // 没有可更新的时候退出
                break;
            }

            // 更新数据
            updateData.forEach((addressId,caseIds) -> {
                TrafficCaseInfo trafficCaseInfo = new TrafficCaseInfo();
                if ("province".equals(type)) {
                    trafficCaseInfo.setProvinceId(addressId);
                } else if ("city".equals(type)) {
                    trafficCaseInfo.setCityId(addressId);
                } else {
                    trafficCaseInfo.setDistrictId(addressId);
                }
                UpdateWrapper<TrafficCaseInfo> updateWrapper = new UpdateWrapper<>();
                updateWrapper.in("id",caseIds);
                trafficCaseInfoMapper.update(trafficCaseInfo,updateWrapper);
            });
        }
    }

    private Map<Integer, List<Integer>> generateUpdateData(List<TrafficCaseInfo> records,Map<String, Address> addressMap,String type) {
        // 键是省的id，值对应该省的case_info的id数组，更新这些id数据的province_id为键
        HashMap<Integer, List<Integer>> updateData = new HashMap<>();
        records.forEach(caseInfo -> {
            String area;
            switch (type) {
                default:
                case "province":
                    area = caseInfo.getCaseProvince();
                    break;
                case "city":
                    area = caseInfo.getCaseCity();
                    break;
                case "district":
                    area = caseInfo.getCaseArea();
                    break;
            }
            Address address = addressMap.get(area);
            if (address == null) {
                // 可能名称不一致，再模糊查一遍
                QueryWrapper<Address> queryWrapper = new QueryWrapper<>();
                Address p = addressMapper.selectOne(queryWrapper.likeRight("name", area)
                        .eq("level", type),false);
                if (p == null) {
                    // 没查到就return，不做处理了
                    return;
                }
                address = p;
            }
            List<Integer> v = updateData.get(address.getId());
            if (v != null) {
                v.add(caseInfo.getId());
            } else {
                ArrayList<Integer> caseIds = new ArrayList<>();
                caseIds.add(caseInfo.getId());
                updateData.put(address.getId(),caseIds);
            }
        });
        return updateData;
    }
}
